package cc.comac.mom.util;


import com.google.common.base.Strings;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Data
public class ImportUtil {
    public <T> List<T> execute(MultipartFile file, int startIndex, Class<T> clz) throws Exception {
        List<T> result = new ArrayList<>();
        if (file == null) {
            throw new RuntimeException("导入的文件不能为空!");
        }

        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            throw new RuntimeException("文件转化流失败!");
        }

        Workbook workbook = null;
        try {
            String fileName = file.getOriginalFilename();
            if (fileName.toLowerCase().endsWith("xls")) {
                workbook = new HSSFWorkbook(inputStream);
            } else if (fileName.toLowerCase().endsWith("xlsx")) {
                workbook = new XSSFWorkbook(inputStream);
            } else {
                throw new RuntimeException("上传的文件需为Excel文件!");
            }
        } catch (IOException e) {
            throw new RuntimeException("解析Excel文件失败!");
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        List<ColumnInfo> columnInfos = getColumnInfos(workbook, clz);

        Integer activeIndex = workbook.getActiveSheetIndex();
        Sheet sheet = workbook.getSheetAt(activeIndex);
        for (int i = startIndex - 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            T t = clz.newInstance();
            for (ColumnInfo columnInfo : columnInfos) {
                String value = getCellValue(row.getCell(columnInfo.getIndex()));
                Field field = ReflectionUtil.getDeclaredField(clz, columnInfo.getKey());
                ReflectionUtil.setFieldValue(t, columnInfo.getKey(), getValue(value, field));
            }
            result.add(t);
        }

        if (inputStream != null) {
            inputStream.close();
        }

        return result;
    }

    public <T> List<T> execute(MultipartFile file, Class<T> clz) throws Exception {
        return execute(file, 2, clz);
    }

    private Object getValue(String value, Field field) {
        if (StringUtils.isEmpty(value)) {
            return value;
        }
        Class type = field.getType();
        if (type.equals(Boolean.class) || boolean.class.equals(type)) {
            if ("是".equals(value) || "y".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "1".equals(value)) {
                return true;
            } else {
                return false;
            }
        } else if (type.equals(Integer.class) || int.class.equals(type)) {
            return Integer.valueOf(value);
        } else if (type.equals(Double.class) || double.class.equals(type)) {
            return Double.valueOf(value);
        } else if (type.equals(Float.class) || float.class.equals(type)) {
            return Float.valueOf(value);
        } else if (type.equals(Long.class) || long.class.equals(type)) {
            return Long.valueOf(value);
        }
        return value;
    }

    private <T> List<ColumnInfo> getColumnInfos(Workbook workbook, Class<T> clz) {
        List<ColumnInfo> result = new ArrayList<>();

        List<Field> fields = ReflectionUtil.getFieldAnnotatedWith(clz, ExcelColumn.class, null);
        Map<String, Field> fieldMap = fields.stream().collect(Collectors.toMap(
                field -> field.getAnnotation(ExcelColumn.class).text(), field -> field));

        Map<String, Integer> columnIndexMap = new HashMap<>();
        Integer activeIndex = workbook.getActiveSheetIndex();
        Sheet sheet = workbook.getSheetAt(activeIndex);
        Row row = sheet.getRow(sheet.getFirstRowNum());
        Iterator<Cell> cellItr = row.cellIterator();
        while (cellItr.hasNext()) {
            Cell cell = cellItr.next();
            String name = getCellValue(cell);
            if (!Strings.isNullOrEmpty(name)) {
                Integer index = cell.getColumnIndex();
                columnIndexMap.put(name, index);
            }
        }

        for (String name : fieldMap.keySet()) {
            if (columnIndexMap.get(name) != null) {
                Field field = fieldMap.get(name);
                ColumnInfo columnInfo = new ColumnInfo(field.getName(), name,
                        columnIndexMap.get(name), field.getType());
                result.add(columnInfo);
            }
        }

        return result;
    }

    private String getCellValue(Cell cell) {
        if (cell == null) {
            return null;
        }
        switch (cell.getCellType()) {
            case Cell.CELL_TYPE_STRING:
                return cell.getRichStringCellValue().getString();
            case Cell.CELL_TYPE_NUMERIC:
                // 判断是日期时间类型还是数值类型
                if (DateUtil.isCellDateFormatted(cell)) {
                    short format = cell.getCellStyle().getDataFormat();
                    SimpleDateFormat sdf = null;
                    /* 所有日期格式都可以通过getDataFormat()值来判断
                     *     yyyy-MM-dd----- 14
                     *    yyyy年m月d日----- 31
                     *    yyyy年m月--------57
                     *    m月d日  --------- 58
                     *    HH:mm---------- 20
                     *    h时mm分  --------- 32
                     */
                    if (format == 14 || format == 31 || format == 57 || format == 58) {
                        //日期
                        sdf = new SimpleDateFormat("yyyy-MM-dd");
                    } else if (format == 20 || format == 32) {
                        //时间
                        sdf = new SimpleDateFormat("HH:mm");
                    }
                    return sdf.format(cell.getDateCellValue());
                } else {
                    // 对整数进行判断处理
                    double cur = cell.getNumericCellValue();
                    long longVal = Math.round(cur);
                    Object inputValue = null;
                    if (Double.parseDouble(longVal + ".0") == cur) {
                        inputValue = longVal;
                    } else {
                        inputValue = cur;
                    }
                    return String.valueOf(inputValue);
                }
            case Cell.CELL_TYPE_BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            default:
                return null;
        }
    }

    @Data
    @AllArgsConstructor
    private static class ColumnInfo {
        private String key;
        private String name;
        private Integer index;
        private Class type;
    }
}
